package
{
	import flash.events.Event;
	import flash.events.TextEvent;
	import flash.filters.GlowFilter;
	import flash.geom.Point;
	import flash.net.SharedObject;
	import flash.text.TextField;
	import flash.text.TextFieldType;
	import flash.utils.Dictionary;
	
	import org.flixel.*;
	import org.flixel.system.FlxAnim;
	import org.flixel.system.input.Input;
	
	public class MapEditorState extends FlxState
	{	
		//State 
		protected var currentOptionType:int;
		
		protected var selectedOption:String;
		
		protected var selectedImage:FlxSprite;
		
		protected var selectedIconImage:Class;
		
		protected var selectedObjectImage:Class;
		
		protected var dragging:Boolean;
		protected var clearing:Boolean;
		protected var gridOn:Boolean;
		
		protected var lastMouseIndexPos:int;
		protected static const NONE:String = "-1";
		
		protected static const MADE_WALL:String = '1';
		protected static const ROCK_WALL:String = '2';
		protected static const VOID_WALL:String = '3';
		
		protected static const GRASS_TILE:String = '4';
		protected static const WASTE_TILE:String = '5';
		protected static const VOID_TILE:String = '6';
		
		protected static const WATER_SOURCE:String = '20';
		protected static const WIND_SOURCE:String = '21';
		protected static const EARTH_SOURCE:String = '22';
		protected static const LIGHT_SOURCE:String = '23';
		protected static const WATER_UNLIT:String = '24';
		protected static const WIND_UNLIT:String = '25';
		protected static const EARTH_UNLIT:String = '26';
		protected static const LIGHT_UNLIT:String = '27';
		protected static const SOURCE_FORGE:String = '100';
		
		protected static const ICE_OBS:String = '50';
		protected static const FIRE_OBS:String = '51';
		protected static const MUD_OBS:String = '52';
		protected static const STEAM_OBS:String = '53';
		protected static const LIGHTNING_OBS:String = '54';
		protected static const SAND_OBS:String = '55';
		protected static const WOOD_OBS:String = '56';
		protected static const METAL_OBS:String = '57';
		protected static const GLASS_OBS:String = '58';
		protected static const RAINBOW_OBS:String = '59';
		
		protected static const WOLF:String = '70';
		protected static const SCORP:String = '71';
		protected static const WALKER:String = '72';
		
		protected static const CLEAR:String = "CLEAR";
		
		protected static const PLAYER:String = "99";
		
		//Cookie
		protected var localInformation:SharedObject;
		
		//Music and Mute Button.
		protected var music:String;
		protected var musicIco:Music;
		protected var ExitButton:FlxSprite;
		protected var HelpButton:FlxSprite;
		protected var cheatButton:FlxSprite;
		protected var gridToggle:FlxSprite;
		protected var saveButton:FlxSprite;
		protected var openButton:FlxSprite;
		protected var clearAllButton:FlxSprite;
		protected var testButton:FlxSprite;
		protected var submitButton:FlxSprite;
		
		//Editor Buttons
		protected var terrainButton:FlxSprite;
		protected var obstaclesButton:FlxSprite;
		protected var sourcesButton:FlxSprite;
		protected var monstersButton:FlxSprite;
		protected var settingsButton:FlxSprite;
		protected var hoverFilter:GlowFilter;
		protected var selectFilter:GlowFilter;
		
		protected var terrainOverlapped:Boolean = false;
		protected var obstaclesOverlapped:Boolean = false;
		protected var sourcesOverlapped:Boolean = false;
		protected var monstersOverlapped:Boolean = false;
		protected var settingsOverlapped:Boolean = false;
		
		// Game sizing constants
		public static const CELL_SIZE:int = 46;
		public static const ROWS:int = 11;
		public static const COLS:int = 11;
		public static const X_OFFSET:int = 5;
		public static const Y_OFFSET:int = 35;
		
		//Sources constants
		public static const SOURCES_ROWS:int = 5;
		public static const SOURCES_COLS:int = 2;
		public static const SOURCES_X_OFFSET:int = 557;
		public static const SOURCES_Y_OFFSET:int = 85;
		public static const SOURCES_X_SPREAD:int = 10;
		public static const SOURCES_Y_SPREAD:int = 12;
		
		//Monsters constants
		public static const MONSTERS_ROWS:int = 1;
		public static const MONSTERS_COLS:int = 3;
		public static const MONSTERS_X_OFFSET:int = 529;
		public static const MONSTERS_Y_OFFSET:int = 85;
		public static const MONSTERS_X_SPREAD:int = 10;
		public static const MONSTERS_Y_SPREAD:int = 12;
		
		//Terrain constants
		public static const TERRAIN_ROWS:int = 1;
		public static const TERRAIN_COLS:int = 3;
		public static const TERRAIN_X_OFFSET:int = 529;
		public static const TERRAIN_Y_OFFSET:int = 85;
		public static const TERRAIN_X_SPREAD:int = 10;
		public static const TERRAIN_Y_SPREAD:int = 12;
		
		//Obstacles constants
		public static const OBSTACLES_ROWS:int = 4;
		public static const OBSTACLES_COLS:int = 3;
		public static const OBSTACLES_X_OFFSET:int = 529;
		public static const OBSTACLES_Y_OFFSET:int = 85;
		public static const OBSTACLES_X_SPREAD:int = 10;
		public static const OBSTACLES_Y_SPREAD:int = 12;
		
		//Type constants
		public static const MAIN:int = 0;
		public static const SOURCES:int = 1;
		public static const MONSTERS:int = 2;
		public static const TERRAIN:int = 3;
		public static const OBSTACLES:int = 4;
		public static const SETTINGS:int = 5;
		
		//Type Limits
		public static const SOURCES_LIMIT:int = 9;
		public static const MONSTERS_LIMIT:int = 3;
		public static const TERRAIN_LIMIT:int = 3;
		public static const OBSTACLES_LIMIT:int = 10;
		
		// includes the bounding bars that contribute to the offset.
		public static const GRID_WIDTH:int = (CELL_SIZE * COLS) + (2 * X_OFFSET);
		public static const GRID_HEIGHT:int = (CELL_SIZE * ROWS) + (2 * Y_OFFSET);
		
		protected var Canvas:FlxGroup;
		protected var OptionsBGGrid:FlxGroup;
		protected var OptionsGrid:FlxGroup;
		
		protected var Grid:FlxSprite;
		
		//options are the name i chose for the different elements you can put in the gmae
		
		//stores the images at CATEGORY*100 + the index for the option
		protected static var optionsImage:Dictionary = new Dictionary();
		
		//the final images, animations from option number to image
		protected static var objectImage:Dictionary = new Dictionary();
		
		//stores the string value of the option which will be the text representation of the map
		protected static var optionsString:Dictionary = new Dictionary();
		
		optionsImage[TERRAIN*100 + 0] = Res.editorT0;
		optionsImage[TERRAIN*100 + 1] = Res.editorT1;
		optionsImage[TERRAIN*100 + 2] = Res.editorT2;
		optionsString[TERRAIN*100 + 0] = MADE_WALL;
		optionsString[TERRAIN*100 + 1] = ROCK_WALL;
		optionsString[TERRAIN*100 + 2] = VOID_WALL;
		objectImage[MADE_WALL] = Res.grassWalls;
		objectImage[ROCK_WALL] = Res.barrenWalls;
		objectImage[VOID_WALL] = Res.voidWalls;
		
		optionsImage[OBSTACLES*100 + 0] = Res.editorO0;
		optionsImage[OBSTACLES*100 + 1] = Res.editorO1;
		optionsImage[OBSTACLES*100 + 2] = Res.editorO2;
		optionsImage[OBSTACLES*100 + 3] = Res.editorO3;
		optionsImage[OBSTACLES*100 + 4] = Res.editorO4;
		optionsImage[OBSTACLES*100 + 5] = Res.editorO5;
		optionsImage[OBSTACLES*100 + 6] = Res.editorO6;
		optionsImage[OBSTACLES*100 + 7] = Res.editorO7;
		optionsImage[OBSTACLES*100 + 8] = Res.editorO8;
		optionsImage[OBSTACLES*100 + 9] = Res.editorO9;
		optionsString[OBSTACLES*100 + 0] = MUD_OBS;
		optionsString[OBSTACLES*100 + 1] = SAND_OBS;
		optionsString[OBSTACLES*100 + 2] = STEAM_OBS;
		optionsString[OBSTACLES*100 + 3] = FIRE_OBS;
		optionsString[OBSTACLES*100 + 4] = ICE_OBS;
		optionsString[OBSTACLES*100 + 5] = LIGHTNING_OBS;
		optionsString[OBSTACLES*100 + 6] = WOOD_OBS;
		optionsString[OBSTACLES*100 + 7] = GLASS_OBS;
		optionsString[OBSTACLES*100 + 8] = METAL_OBS;
		optionsString[OBSTACLES*100 + 9] = RAINBOW_OBS;
		objectImage[MUD_OBS] = Res.mudObsAnim;
		objectImage[SAND_OBS] = Res.sandObsAnim;
		objectImage[STEAM_OBS] = Res.steamObsAnim;
		objectImage[FIRE_OBS] = Res.fireWallAnim;
		objectImage[ICE_OBS] = Res.iceObsAnim;
		objectImage[LIGHTNING_OBS] = Res.lightningObsAnim;
		objectImage[WOOD_OBS] = Res.pitImages;
		objectImage[GLASS_OBS] = Res.glassObsAnim;
		objectImage[METAL_OBS] = Res.metalObsAnim;
		objectImage[RAINBOW_OBS] = Res.rainbowObsAnim;
		
		optionsImage[SOURCES*100 + 0] = Res.editorS0;
		optionsImage[SOURCES*100 + 1] = Res.editorS1;
		optionsImage[SOURCES*100 + 2] = Res.editorS2;
		optionsImage[SOURCES*100 + 3] = Res.editorS3;
		optionsImage[SOURCES*100 + 4] = Res.editorS4;
		optionsImage[SOURCES*100 + 5] = Res.editorS5;
		optionsImage[SOURCES*100 + 6] = Res.editorS6;
		optionsImage[SOURCES*100 + 7] = Res.editorS7;
		optionsImage[SOURCES*100 + 8] = Res.editorS8;
		optionsString[SOURCES*100 + 0] = LIGHT_SOURCE;
		optionsString[SOURCES*100 + 1] = LIGHT_UNLIT;
		optionsString[SOURCES*100 + 2] = EARTH_SOURCE;
		optionsString[SOURCES*100 + 3] = EARTH_UNLIT;
		optionsString[SOURCES*100 + 4] = WATER_SOURCE;
		optionsString[SOURCES*100 + 5] = WATER_UNLIT;
		optionsString[SOURCES*100 + 6] = WIND_SOURCE;
		optionsString[SOURCES*100 + 7] = WIND_UNLIT;
		optionsString[SOURCES*100 + 8] = SOURCE_FORGE;
		objectImage[LIGHT_SOURCE] = Res.LightOnSource;
		objectImage[LIGHT_UNLIT] = Res.LightOffSource;
		objectImage[EARTH_SOURCE] = Res.EarthOnSource;
		objectImage[EARTH_UNLIT] = Res.EarthOffSource;
		objectImage[WATER_SOURCE] = Res.WaterOnSource;
		objectImage[WATER_UNLIT] = Res.WaterOffSource;
		objectImage[WIND_SOURCE] = Res.WindOnSource;
		objectImage[WIND_UNLIT] = Res.WindOffSource;
		objectImage[SOURCE_FORGE] = Res.sfNormalAnim;
		
		optionsImage[MONSTERS*100 + 0] = Res.editorM0;
		optionsImage[MONSTERS*100 + 1] = Res.editorM1;
		optionsImage[MONSTERS*100 + 2] = Res.editorM2;
		optionsString[MONSTERS*100 + 0] = WOLF;
		optionsString[MONSTERS*100 + 1] = SCORP;
		optionsString[MONSTERS*100 + 2] = WALKER;
		objectImage[WOLF] = Res.grassMonsterImage;
		objectImage[SCORP] = Res.barrenMonsterImage;
		objectImage[WALKER] = Res.voidMonsterImage;
		
		optionsImage[SETTINGS*100 + 0] = Res.playerStill;
		optionsString[SETTINGS*100 + 0] = PLAYER;
		objectImage[PLAYER] = Res.playerStill;
		
		
		optionsImage[TERRAIN*100 + TERRAIN_LIMIT] = Res.clearImage;
		optionsImage[OBSTACLES*100 + OBSTACLES_LIMIT] = Res.clearImage;
		optionsImage[SOURCES*100 + SOURCES_LIMIT] = Res.clearImage;
		optionsImage[MONSTERS*100 + MONSTERS_LIMIT] = Res.clearImage;
		optionsString[TERRAIN*100 + TERRAIN_LIMIT] = CLEAR;
		optionsString[OBSTACLES*100 + OBSTACLES_LIMIT] = CLEAR;
		optionsString[SOURCES*100 + SOURCES_LIMIT] = CLEAR;
		optionsString[MONSTERS*100 + MONSTERS_LIMIT] = CLEAR;
		objectImage[CLEAR] = Res.Black;
		
		protected var createdMap:Dictionary;
		protected var createdMapSprites:Array;
		
		//for highlighting selected options... another necessary dictionary...
		protected var optionBGs:Dictionary;
		protected var currentBG:FlxTileblock;
		
		//cheat sheet
		protected var cheatSheetOpen:Boolean;
		protected var cheatSheet:CheatSheet;
		
		protected var Settings:FlxGroup;
		protected var curTileSet:int;
		
		protected static const GRASS_TILES:int = 0;
		protected static const WASTE_TILES:int = 1;
		protected static const VOID_TILES:int = 2;
		
		protected var TileSet:FlxGroup;
		protected var Border:FlxGroup;
		
		protected var CurrentStartPosition:int;
		protected var changingStartPosition:Boolean;
		
		protected var upArrows:int;
		protected var downArrows:int;
		protected var rightArrows:int;
		protected var leftArrows:int;
		protected var chickens:int;
		
		protected var settingsBGGrid:FlxGroup;
		protected var settingsGrid:FlxGroup;
		protected var settingsBGs:Dictionary;
		
		protected var upArrowText:TextField = new TextField();
		protected var downArrowText:TextField = new TextField();
		protected var rightArrowText:TextField = new TextField();
		protected var leftArrowText:TextField = new TextField();
		protected var chickensText:TextField = new TextField();
		
		protected var validated:Boolean;
		protected var testable:Boolean;
		
		//for popups
		protected var modalUp:Boolean;
		protected var clearAll:Boolean;
		protected var saveMap:Boolean;
		protected var openMap:Boolean;
		protected var submitting:Boolean;
		
		protected var savePopup:ModalSavePopup;
		protected var clearAllPopup:ModalAreYouSurePopup;
		protected var openPopup:ModalOpenPopup;
		protected var submitPopup:ModalSubmitPopup;
		
		protected var darkCount:int;
		
		//achievements
		protected var achievesTimer:Number;
		protected var achievDisplayed:Boolean;
		protected var achievCurr:AchievementReport;
		
		public function MapEditorState(spec:PuzzleSpecification, validated:Boolean = false)
		{
			
			super();
			
			this.validated = validated;
			dragging = false;
			clearing = false;
			gridOn = true;
			changingStartPosition = false;
			modalUp = false;
			darkCount = 0;
			
			//initialize counts
			upArrows = 0;
			downArrows = 0;
			rightArrows = 0;
			leftArrows = 0;
			chickens = 0;
			
			lastMouseIndexPos = -1;
			createdMap = new Dictionary();
			createdMapSprites = new Array();
			currentBG = new FlxTileblock(0,0,1,1);
			
			//cheat sheet
			cheatSheet = new CheatSheet(40);
			cheatSheet.prepare(false,40);
			
			this.add(new FlxSprite(0,0, Res.bg));
			
			//Initiate music and player options to turn it off.
			localInformation = SharedObject.getLocal("elementalGameInfo");
			
			music = Res.gokun;
			
			//hint box and replay
			ExitButton = new FlxSprite(700-55, 5, Res.ExitButton);
			//HelpButton = new FlxSprite(700-110, 5, Res.HelpButton);
			
			//Other buttons
			gridToggle = new FlxSprite(441, 546, Res.gridToggle);
			saveButton = new FlxSprite(5, 550, Res.saveButton);
			openButton = new FlxSprite(5, 580, Res.openButton);
			clearAllButton = new FlxSprite(5, 610, Res.clearAllButton);
			
			if (spec != null && validated) {
				testButton = new FlxSprite(110, 555, Res.testButton);
				submitButton = new FlxSprite(220, 555, Res.submitButton);
			} else {
				testButton = new FlxSprite(110, 555, Res.preTestButton);
				submitButton = new FlxSprite(220, 555, Res.presubmitButton);
			}
			
			musicIco = new Music(615,5);
			
			//editor button init
			terrainButton = new FlxSprite(7 + GRID_WIDTH, Y_OFFSET + 5, Res.TerrainButtonNorm);
			obstaclesButton = new FlxSprite(7 + GRID_WIDTH + 35, Y_OFFSET + 5, Res.ObstaclesButtonNorm);
			sourcesButton = new FlxSprite(7 + GRID_WIDTH + 70, Y_OFFSET + 5, Res.SourcesButtonNorm);
			monstersButton = new FlxSprite(7 + GRID_WIDTH + 105, Y_OFFSET + 5, Res.MonstersButtonNorm);
			settingsButton = new FlxSprite(7 + GRID_WIDTH + 140, Y_OFFSET + 5, Res.SettingsButtonSelected);
			hoverFilter = new GlowFilter(0xFFFFBE, 0.6, 3, 3, 3,1,true);
			selectFilter = new GlowFilter(0xDD22DD, 0.8, 10, 10, 3,1,true);
			
			
			cheatButton = new FlxSprite(0, 0, Res.ComboButton);
			cheatButton.x = FlxG.width - cheatButton.width - 10;
			cheatButton.y = FlxG.height - cheatButton.height - 10;
			
			Canvas = new FlxGroup();
			Border = new FlxGroup();
			TileSet = new FlxGroup();
			
			
			Border.add(new FlxSprite(0, Y_OFFSET - 5, Res.topBoundImage));
			Border.add(new FlxSprite(0, GRID_HEIGHT - Y_OFFSET, Res.bottomBoundImage));
			Border.add(new FlxSprite(0, Y_OFFSET - 5, Res.leftBoundImage));
			Border.add(new FlxSprite(GRID_WIDTH - X_OFFSET, Y_OFFSET - 5, Res.rightBoundImage));
			
			
			if (spec != null) {
				var a:Array = spec.getArrows();
				upArrows = a[0];
				downArrows = a[1];
				leftArrows = a[2];
				rightArrows = a[3];
				chickens = spec.getChickens().length;
				curTileSet = spec.getTileSet();
				//TODO uid
				
				var mapArray:Array = spec.getMap().split(",");
				
				//Parse and create map
				for (var i:int = 0; i < ROWS; i++) {
					for (var j:int = 0; j < COLS; j++) {
						var index:int = (i*COLS) + j;
						var pos:Point = getPointFromIndex(index, MAIN);
						var g:FlxTileblock;
						g = new FlxTileblock(pos.x, pos.y, CELL_SIZE, CELL_SIZE);
						if (curTileSet == VOID_TILES) {
							g.loadTiles(Res.voidTiles, CELL_SIZE, CELL_SIZE, 0);
						} else if (curTileSet == WASTE_TILES) {
							g.loadTiles(Res.barrenTiles, CELL_SIZE, CELL_SIZE, 0);
						} else {
							g.loadTiles(Res.grassTiles, CELL_SIZE, CELL_SIZE, 0);
						}
						TileSet.add(g);
						createdMap[index] = mapArray[index];
						if (mapArray[index] == "0") {
							createdMap[index] = NONE;
						} else if (mapArray[index] == "1" || mapArray[index] == "2" || mapArray[index] == "3") {
							var b:FlxTileblock;
							b = new FlxTileblock(pos.x, pos.y, CELL_SIZE,CELL_SIZE);
							if (mapArray[index] == "1") {
								b.loadTiles(Res.grassWalls, CELL_SIZE, CELL_SIZE, 0);
							} else if (mapArray[index] == "2") {
								b.loadTiles(Res.barrenWalls, CELL_SIZE, CELL_SIZE, 0);
							} else {
								b.loadTiles(Res.voidWalls, CELL_SIZE, CELL_SIZE, 0);
							}
							b.loadTiles(objectImage[mapArray[index]],CELL_SIZE,CELL_SIZE,0);
							createdMapSprites[index] = b;
							Canvas.add(b);
						} else if (mapArray[index] == "100") {
							var sf:FlxSprite = new FlxSprite(pos.x, pos.y, Res.blankImage);
							sf.loadGraphic(Res.sfNormalAnim, true, false,46,46,false);
							sf.addAnimation("norm", [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], 6);
							sf.play("norm");
							createdMapSprites[index] = sf;
							Canvas.add(sf);
						} else if (int(mapArray[index]) >= 20 && int(mapArray[index]) <= 23) {//mapArray[index] == "20") {
							var s:FlxSprite = new FlxSprite(pos.x, pos.y, Res.blankImage);
							s.loadGraphic(objectImage[mapArray[index]], true, false,46,46,false);
							s.addAnimation("norm", [0,1,2,3,4], 4);
							s.play("norm");
							createdMapSprites[index] = s;
							Canvas.add(s);
						} else if (int(mapArray[index]) >= 24 && int(mapArray[index]) <= 27) {//mapArray[index] == "24" || mapArray[index] == "28") {
							if (int(mapArray[index]) >= int(WATER_UNLIT) && int(mapArray[index]) <= int(LIGHT_UNLIT)) {
								darkCount++;
							}
							var sOff:FlxSprite = new FlxSprite(pos.x, pos.y, Res.blankImage);
							sOff.loadGraphic(objectImage[mapArray[index]], false, false,46,46,false);
							createdMapSprites[index] = sOff;
							Canvas.add(sOff);
						} else if (mapArray[index] == "99") {
							CurrentStartPosition = index;
							var p:FlxSprite = new FlxSprite(pos.x,pos.y, Res.blankImage);
							p.loadGraphic(Res.playerStill, false, false, 46,46,false);
							createdMap[CurrentStartPosition] = PLAYER;
							createdMapSprites[CurrentStartPosition] = p;
							Canvas.add(p);
						} else if (int(mapArray[index]) >= 50 && int(mapArray[index]) <= 69){
							if (int(mapArray[index]) == 56) {
								var pit:FlxTileblock;
								pit = new FlxTileblock(pos.x, pos.y, CELL_SIZE,CELL_SIZE);
								pit.loadTiles(Res.pitImages, 46, 46, 0);
								createdMapSprites[index] = pit;
								Canvas.add(pit);
							} else {
								var obs:FlxSprite = new FlxSprite(pos.x,pos.y,Res.blankImage);
								obs.loadGraphic(objectImage[mapArray[index]],true,false, 46,46,false);
								obs.addAnimation("norm", [0,1,2,3,4,5,6,7], 8);
								obs.play("norm");
								createdMapSprites[index] = obs;
								Canvas.add(obs);
							}
						} else if (int(mapArray[index]) >= 70 && int(mapArray[index]) <= 90) {
							var mon:FlxSprite = new FlxSprite(pos.x + 8,pos.y + 8,Res.blankImage);
							mon.loadGraphic(objectImage[mapArray[index]],true,false, 30,30,false);
							mon.addAnimation("norm", [0,1,2,3], 4);
							mon.play("norm");
							createdMapSprites[index] = mon;
							Canvas.add(mon);
						}
					}
				}
			} else {
				//Main Grid
				for (var k:int = 0; k < ROWS; k++) {
					for (var l:int = 0; l < COLS; l++) {
						var canvasIndex:int = (k*COLS) + l;
						var position:Point = getPointFromIndex(canvasIndex,MAIN);
						var block:FlxTileblock;
						block = new FlxTileblock(position.x, position.y, CELL_SIZE,CELL_SIZE);
						block.loadTiles(Res.grassTiles, CELL_SIZE, CELL_SIZE, 0);
						TileSet.add(block);
						createdMap[canvasIndex] = NONE;
						if (canvasIndex == 0) {
							var startPos:FlxSprite = new FlxSprite(position.x,position.y, Res.blankImage);
							startPos.loadGraphic(Res.playerStill, false, false, 46,46,false);
							Canvas.add(startPos);
							CurrentStartPosition = canvasIndex;
							createdMapSprites[canvasIndex] = startPos;
							createdMap[canvasIndex] = PLAYER;
						}
					}
				}
			}
			
			//for settings
			settingsBGGrid = new FlxGroup();
			settingsBGs = new Dictionary();
			settingsGrid = new FlxGroup();
			createSettings();
			
			
			selectedImage = new FlxSprite(0,0,Res.blankImage);
			
			Grid = new FlxSprite(X_OFFSET, Y_OFFSET, Res.EditorGrip);
			this.add(TileSet);
			this.add(Canvas);
			this.add(Border);
			this.add(Grid);
			this.add(selectedImage);
			//SIDE BAR IMPORTANT PLACE
			this.add(new FlxSprite(516,0,Res.SideBar));
			
			this.add(musicIco);
			this.add(ExitButton);
			this.add(HelpButton);
			this.add(gridToggle);
			this.add(saveButton);
			this.add(openButton);
			this.add(clearAllButton);
			this.add(testButton);
			this.add(submitButton);
			
			this.add(terrainButton);
			this.add(obstaclesButton);
			this.add(sourcesButton);
			this.add(monstersButton);
			this.add(settingsButton);
			
			this.add(cheatButton);
			
			savePopup = new ModalSavePopup(getCurMap());
			
			drawOptions(SETTINGS);
		
			//we're being stalkish so we want to know when player enters MapEditor
			Elemental.Log.startDquest(Logging.MAP_EDITOR);
		}
		
		private function createSettings():void {
			Settings = new FlxGroup();
			var playerText:FlxText = new FlxText(520, 100, 180, "Player Starting Position", false);
			playerText.setFormat("Arial", 14, 0x000000);
			
			Settings.add(playerText);
			
			var terrainText:FlxText = new FlxText(520, 175, 180, "Background Tileset", false);
			terrainText.setFormat("Arial", 14, 0x000000);
			
			Settings.add(terrainText);
			
			var aText:FlxText = new FlxText(520, 250, 180, "Arrow Counts", false);
			aText.setFormat("Arial", 14, 0x000000);
			
			Settings.add(aText);
			
			var cText:FlxText = new FlxText(520, 325, 180, "Chicken Count", false);
			cText.setFormat("Arial", 14, 0x000000);
			
			Settings.add(cText);
			
			var playerBG:FlxTileblock = new FlxTileblock(520,120,60,60);
			playerBG.loadGraphic(Res.iconBG, false,false,60,60,false);
			var player:FlxTileblock = new FlxTileblock(527, 127,46,46);
			player.loadGraphic(Res.playerStill, false, false, 46,46,false);
			
			var grassBG:FlxTileblock = new FlxTileblock(520,195,60,60);
			grassBG.loadGraphic(Res.iconBG, false,false,60,60,false);
			var grassTile:FlxTileblock = new FlxTileblock(527, 202,46,46);
			grassTile.loadGraphic(Res.editorT3, false, false, 46,46,false);
			
			var wasteBG:FlxTileblock = new FlxTileblock(576,195,60,60);
			wasteBG.loadGraphic(Res.iconBG, false,false,60,60,false);
			var wasteTile:FlxTileblock = new FlxTileblock(583, 202,46,46);
			wasteTile.loadGraphic(Res.editorT4, false, false, 46,46,false);
			
			var voidBG:FlxTileblock = new FlxTileblock(632,195,60,60);
			voidBG.loadGraphic(Res.iconBG, false,false,60,60,false);
			var voidTile:FlxTileblock = new FlxTileblock(639, 202,46,46);
			voidTile.loadGraphic(Res.editorT5, false, false, 46,46,false);
			
			var upArrow:FlxSprite = new FlxSprite(516, 260, Res.BeamArrow);
			var downArrow:FlxSprite = new FlxSprite(559, 260, Res.BeamArrow);
			var rightArrow:FlxSprite = new FlxSprite(602, 260, Res.BeamArrow);
			var leftArrow:FlxSprite = new FlxSprite(645, 260, Res.BeamArrow);
			var chickenImage:FlxSprite = new FlxSprite(525, 350, Res.chickenImage);
			upArrow.scale = new FlxPoint(.5,.5);
			downArrow.scale = new FlxPoint(.5,.5);
			downArrow.angle = 180;
			rightArrow.scale = new FlxPoint(.5,.5);
			rightArrow.angle = 90;
			leftArrow.scale = new FlxPoint(.5,.5);
			leftArrow.angle = 270;
			
			var textBG1:FlxSprite = new FlxSprite(525,300,Res.textBG);
			upArrowText.type = TextFieldType.INPUT;
			upArrowText.x = 530;
			upArrowText.y = 302;
			upArrowText.width = 30;
			upArrowText.height = 20;
			upArrowText.maxChars = 2;
			upArrowText.multiline = false;
			upArrowText.restrict = "0-9";
			upArrowText.text = "";
			upArrowText.text = new String(upArrows);
			upArrowText.addEventListener(Event.CHANGE, updateUpArrowCount);
			
			var textBG2:FlxSprite = new FlxSprite(568,300,Res.textBG);
			downArrowText.type = TextFieldType.INPUT;
			downArrowText.x = 573;
			downArrowText.y = 302;
			downArrowText.width = 30;
			downArrowText.height = 20;
			downArrowText.maxChars = 2;
			downArrowText.multiline = false;
			downArrowText.restrict = "0-9";
			downArrowText.text = "";
			downArrowText.text = new String(downArrows);
			downArrowText.addEventListener(Event.CHANGE, updateDownArrowCount);
			
			var textBG3:FlxSprite = new FlxSprite(611,300,Res.textBG);
			rightArrowText.type = TextFieldType.INPUT;
			rightArrowText.x = 616;
			rightArrowText.y = 302;
			rightArrowText.width = 30;
			rightArrowText.height = 20;
			rightArrowText.maxChars = 2;
			rightArrowText.multiline = false;
			rightArrowText.restrict = "0-9";
			rightArrowText.text = "";
			rightArrowText.text = new String(rightArrows);
			rightArrowText.addEventListener(Event.CHANGE, updateRightArrowCount);
			
			var textBG4:FlxSprite = new FlxSprite(654,300,Res.textBG);
			leftArrowText.type = TextFieldType.INPUT;
			leftArrowText.x = 659;
			leftArrowText.y = 302;
			leftArrowText.width = 30;
			leftArrowText.height = 20;
			leftArrowText.maxChars = 2;
			leftArrowText.multiline = false;
			leftArrowText.restrict = "0-9";
			leftArrowText.text = "";
			leftArrowText.text = new String(leftArrows);
			//leftArrowText.addEventListener(TextEvent.TEXT_INPUT, updateLeftArrowCount);
			leftArrowText.addEventListener(Event.CHANGE, updateLeftArrowCount);
			
			var textBG5:FlxSprite = new FlxSprite(568,355,Res.textBG);
			chickensText.type = TextFieldType.INPUT;
			chickensText.x = 576;
			chickensText.y = 357;
			chickensText.width = 30;
			chickensText.height = 20;
			chickensText.maxChars = 1;
			chickensText.multiline = false;
			chickensText.restrict = "0-5";
			chickensText.text = "";
			chickensText.text = new String(chickens);
			//chickensText.addEventListener(TextEvent.TEXT_INPUT, updateChickenCount);
			chickensText.addEventListener(Event.CHANGE, updateChickenCount);
			
			settingsBGGrid.add(upArrow);
			settingsBGGrid.add(downArrow);
			settingsBGGrid.add(rightArrow);
			settingsBGGrid.add(leftArrow);
			settingsBGGrid.add(chickenImage);
			settingsBGGrid.add(textBG1);
			settingsBGGrid.add(textBG2);
			settingsBGGrid.add(textBG3);
			settingsBGGrid.add(textBG4);
			settingsBGGrid.add(textBG5);
			settingsBGGrid.add(playerBG);
			settingsBGs[0] = playerBG;
			settingsBGGrid.add(grassBG);
			settingsBGs[1] = grassBG;
			settingsBGGrid.add(wasteBG);
			settingsBGs[2] = wasteBG;
			settingsBGGrid.add(voidBG);
			settingsBGs[3] = voidBG;
			
			settingsGrid.add(player);
			settingsGrid.add(grassTile);
			settingsGrid.add(wasteTile);
			settingsGrid.add(voidTile);
		}
		
		public override function update():void {
			
			super.update();
			musicIco.updateMusic(music);
			if (modalUp) {
				if (clearAll) {
					if (clearAllPopup.finishedPopup()) {
						if (clearAllPopup.wasYes()) {
							clearMap();
						}
						this.remove(clearAllPopup);	
						modalUp = false;
						clearAll = false;
					}
					
				} else if (saveMap) {
					if (savePopup.finishedPopup()) {
						if (!savePopup.wasSaved()) savePopup.removeNameText();
						this.remove(savePopup);
						modalUp = false;
						saveMap = false;
					}
				} else if (openMap) {
					if (openPopup.finishedPopup()) {
						if (openPopup.wasOpened()) {
							if (currentOptionType == SETTINGS) {
								FlxG.stage.removeChild(upArrowText);
								FlxG.stage.removeChild(downArrowText);
								FlxG.stage.removeChild(leftArrowText);
								FlxG.stage.removeChild(rightArrowText);
								FlxG.stage.removeChild(chickensText);
							}
							FlxG.switchState(new MapEditorState(openPopup.getPuzzleSpec(),false));
						}
						this.remove(openPopup);
						modalUp = false;
						openMap = false;
					}
				} else if (submitting) {
					if (submitPopup.finishedPopup()) {
						if (submitPopup.submitted()) {
							//log it
							
						} else {
							submitPopup.hideNameText();
						}
						this.remove(submitPopup);
						modalUp = false;
						submitting = false;
					}
				}
			} else {
				if (FlxG.mouse.justPressed()) {
					checkOptionsChange();
					if (clearing) {
						checkClear();	
					} else {
						checkPlacement();
					}
					checkExit();
					checkOptionSelect();
					checkCheatSheet();
					checkGridToggle();
					checkTest();
					checkClearAll();
					checkOpen();
					checkSave();
					checkSubmit();
				}
				if (FlxG.mouse.justReleased() || !mouseOverCanvas()) {
					dragging = false;
				}
				if (dragging) {
					if (clearing) {
						checkClear();
					} else {
						checkPlacement();
					}
				}
				
				if (darkCount == 0 && testable) {
					testButton.loadGraphic(Res.preTestButton, false, false, 100, 75, false);
					testable = false;
				}
				
				if (darkCount > 0 && !testable) {
					testButton.loadGraphic(Res.testButton, false, false, 100, 75, false);
					testable = true;
				}
				
				checkHover();
				updateSelectedImage();
			}
			
			updateAchievementDisplay();
		}
		
		/**
		 * handles everything with displaying an achievement in game
		 */
		private function updateAchievementDisplay():void {
			if (Elemental.MODE != Elemental.FACEBOOK_MODE) {
				return;
			}
			if (!achievDisplayed) {
				if (Elemental.achievements.hasAchievementToReport()) {
					achievCurr = Elemental.achievements.getNextAchievementToReport();
					this.add(achievCurr);
					achievesTimer = 0;
					achievDisplayed = true;
				}
			} else if (achievesTimer > 2.2) {
				this.remove(achievCurr, true);
				if (Elemental.achievements.hasAchievementToReport()) {
					achievCurr = Elemental.achievements.getNextAchievementToReport();
					this.add(achievCurr);
					achievesTimer = 0;
				} else {
					achievDisplayed = false;
					achievesTimer = 0;
				}
			} else {
				achievesTimer += FlxG.elapsed;
			}
		}
		
		private function checkSubmit():void {
			if (validated && submitButton.overlapsPoint(FlxG.mouse.x, FlxG.mouse.y)) {
				modalUp = true;
				submitting = true;
				submitPopup = new ModalSubmitPopup(getCurMap());
				submitPopup.displayNameText();
				this.add(submitPopup);
			}
		}
		
		private function checkOpen():void {
			if (openButton.overlapsPoint(FlxG.mouse.x, FlxG.mouse.y)) {
				modalUp = true;
				openMap = true;
				openPopup = new ModalOpenPopup();
				this.add(openPopup);
			}
		}
		
		private function checkSave():void {
			if (saveButton.overlapsPoint(FlxG.mouse.x, FlxG.mouse.y)) {
				modalUp = true;
				saveMap = true;
				savePopup = new ModalSavePopup(getCurMap());
				savePopup.displayNameText();
				this.add(savePopup);
			}
		}
		
		private function clearMap():void {
			for (var k:int = 0; k < ROWS; k++) {
				for (var l:int = 0; l < COLS; l++) {
					var canvasIndex:int = (k*COLS) + l;
					createdMap[canvasIndex] = NONE;
					Canvas.remove(createdMapSprites[canvasIndex], true);
					if (canvasIndex == 0) {
						var position:Point = getPointFromIndex(canvasIndex,MAIN);
						var startPos:FlxSprite = new FlxSprite(position.x,position.y, Res.blankImage);
						startPos.loadGraphic(Res.playerStill, false, false, 46,46,false);
						Canvas.add(startPos);
						CurrentStartPosition = canvasIndex;
						createdMapSprites[canvasIndex] = startPos;
						createdMap[canvasIndex] = PLAYER;
					}
				}
			}
			darkCount = 0;
			upArrows = 0;
			downArrows = 0;
			leftArrows = 0;
			rightArrows = 0;
			chickens = 0;
			upArrowText.text = "0";
			downArrowText.text = "0";
			leftArrowText.text = "0";
			rightArrowText.text = "0";
			chickensText.text = "0";
		}
		
		private function checkClearAll():void {
			if (clearAllButton.overlapsPoint(FlxG.mouse.x, FlxG.mouse.y)) {
				modalUp = true;
				clearAll = true;
				clearAllPopup = new ModalAreYouSurePopup();
				this.add(clearAllPopup);
			}
		}
		
		private function checkTest():void {
			if (testButton.overlapsPoint(FlxG.mouse.x, FlxG.mouse.y) && isValidPuzzle()) {
				if (currentOptionType == SETTINGS) clearSettings();
				FlxG.switchState(new PuzzlePlayingState(getCurMap(),false, false, false, true)); //"v|99,1,2,3,0,0,1,2,3,24,20,0,1,2,3,0,0,1,2,3,0,20,0,1,2,3,0,0,1,2,3,0,20,0,1,2,3,0,0,1,2,3,0,20,0,1,2,3,0,0,1,2,3,0,20,0,1,2,3,0,0,1,2,3,0,20,0,1,2,3,0,0,1,2,3,0,20,0,1,2,3,0,0,1,2,3,0,20,0,1,2,3,0,0,1,2,3,0,20,0,1,2,3,0,0,1,2,3,0,20,0,1,2,3,0,0,1,2,3,0,20", new Array(1,1,1,1), 0));
			}
		}
		
		/**
		 * A puzzle is testable/valid if it contains a player and at least one unlit source.
		 */
		private function isValidPuzzle():Boolean {
			var hasUnlitSource:Boolean = false;
			var hasPlayer:Boolean = false;
			for (var i:int = 0; i < ROWS * COLS; i++) {
				if (createdMap[i] == "99") {
					hasPlayer = true;
				} else if (int(createdMap[i]) >= 24 && int(createdMap[i]) <= 27) {
					hasUnlitSource = true;
				} 
				
				if (hasUnlitSource && hasPlayer) {
					return true;
				}
			}
			return false;
		}
		
		private function checkGridToggle():void {
			if (gridToggle.overlapsPoint(FlxG.mouse.x, FlxG.mouse.y)) {
				if (gridOn) {
					this.remove(Grid, true);
					gridOn = false;
				} else { 
					this.add(Grid);
					gridOn = true;
				}
			}
		}
		
		private function checkCheatSheet():void {
			if (cheatSheetOpen) {
				cheatSheetOpen = false;
				this.remove(cheatSheet,true);
			} else if (cheatButton != null && cheatButton.overlapsPoint(FlxG.mouse.screenX, FlxG.mouse.screenY)) {
				cheatSheetOpen = true;
				if (!Music.MUTE) {
					FlxG.play(Res.unscrollSound);
				}
				this.add(cheatSheet);
			}
		}
		
		private function mouseOverCanvas():Boolean {
			return FlxG.mouse.x <= 510 && FlxG.mouse.x >= 5 && FlxG.mouse.y <= Y_OFFSET + 505 && FlxG.mouse.y >= Y_OFFSET;
		}
		
		private function checkClear():void {
			if (mouseOverCanvas()) {
				dragging = true;
				var mapIndex:int = getIndexFromPoint(FlxG.mouse.x, FlxG.mouse.y, MAIN);
				if (createdMap[mapIndex] != PLAYER && createdMap[mapIndex] != NONE) {
					if (int(createdMap[mapIndex]) >= int(WATER_UNLIT) && int(createdMap[mapIndex]) <= int(LIGHT_UNLIT)) {
						darkCount--;
					}
					lastMouseIndexPos = -1;
					var p:Point = getPointFromIndex(mapIndex, MAIN);
					createdMap[mapIndex] = NONE;
					
					Canvas.remove(createdMapSprites[mapIndex], true);
					createdMapSprites[mapIndex] = null;
					if (validated) clearValidation();
				}
			}
		}
		
		private function checkPlacement():void {
			if (mouseOverCanvas()) {
				if (changingStartPosition) {
					var index:int = getIndexFromPoint(FlxG.mouse.x, FlxG.mouse.y, MAIN);
					var pos:Point = getPointFromIndex(index, MAIN);
					if (createdMap[index] == NONE) {
						Canvas.remove(createdMapSprites[CurrentStartPosition], true);
						createdMap[CurrentStartPosition] = NONE;
						createdMapSprites[CurrentStartPosition] = null;
						CurrentStartPosition = index;
						var s:FlxSprite = new FlxSprite(pos.x,pos.y, Res.blankImage);
						s.loadGraphic(Res.playerStill, false, false, 46,46,false);
						createdMap[CurrentStartPosition] = PLAYER;
						createdMapSprites[CurrentStartPosition] = s;
						Canvas.add(s);
						if (validated) clearValidation();
					}
				} else {
					dragging = true;
					var mapIndex:int = getIndexFromPoint(FlxG.mouse.x, FlxG.mouse.y, MAIN);
					if (mapIndex != lastMouseIndexPos && createdMap[mapIndex] == NONE) {
						lastMouseIndexPos = mapIndex;
						var p:Point = getPointFromIndex(mapIndex, MAIN);
						createdMap[mapIndex] = selectedOption;
						if (int(selectedOption) >= int(MADE_WALL) && int(selectedOption)<= int(VOID_WALL)) {//terrans
							var ter:FlxTileblock = new FlxTileblock(p.x,p.y,CELL_SIZE,CELL_SIZE);
							ter.loadTiles(selectedObjectImage,CELL_SIZE,CELL_SIZE,0);
							createdMapSprites[mapIndex] = ter;
							Canvas.add(ter);
						} else if ( int(selectedOption) >= int(ICE_OBS)  && int(selectedOption)<= int(RAINBOW_OBS)) {//obstacles
							if (selectedOption == WOOD_OBS) {
								var pit:FlxTileblock;
								pit = new FlxTileblock(p.x, p.y, CELL_SIZE,CELL_SIZE);
								pit.loadTiles(Res.pitImages, 46, 46, 0);
								createdMapSprites[mapIndex] = pit;
								Canvas.add(pit);
							} else {
								var obs:FlxSprite = new FlxSprite(p.x,p.y,Res.blankImage);
								obs.loadGraphic(selectedObjectImage,true,false, 46,46,false);
								obs.addAnimation("norm", [0,1,2,3,4,5,6,7], 8);
								obs.play("norm");
								createdMapSprites[mapIndex] = obs;
								Canvas.add(obs);
							}
						} else if ( (int(selectedOption) >= int(WATER_SOURCE)  && int(selectedOption)<= int(LIGHT_UNLIT)) || int(selectedOption) == int(SOURCE_FORGE)) {//sources
							var sou:FlxSprite = new FlxSprite(p.x,p.y,Res.blankImage);
							sou.loadGraphic(selectedObjectImage,true,false, 46,46,false);
							if (selectedOption == SOURCE_FORGE) {
								sou.addAnimation("norm", [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], 6);
								sou.play("norm");
							} else if (int(selectedOption) <= int(LIGHT_SOURCE)){
								sou.addAnimation("norm", [0,1,2,3], 4);
								sou.play("norm");
							} else {
								darkCount++;
							}
							createdMapSprites[mapIndex] = sou;
							Canvas.add(sou);
						} else if (int(selectedOption) >= int(WOLF)  && int(selectedOption)<= int(WALKER)) {//mobs
							var mon:FlxSprite = new FlxSprite(p.x + 8,p.y + 8,Res.blankImage);
							mon.loadGraphic(selectedObjectImage,true,false, 30,30,false);
							mon.addAnimation("norm", [0,1,2,3], 4);
							mon.play("norm");
							createdMapSprites[mapIndex] = mon;
							Canvas.add(mon);
						}
						if (validated) clearValidation();
					}
				}
			}
		}
		
		private function checkExit():void {
			if (ExitButton.overlapsPoint(FlxG.mouse.screenX,FlxG.mouse.screenY)) {
				if (currentOptionType == SETTINGS) clearSettings();
				if (Elemental.MODE == Elemental.FACEBOOK_MODE) {
					FlxG.switchState(new PlayerRoomState());
				} else {
					FlxG.switchState(new MenuState());
				}
			}
		}
		
		/**
		 * check if an option has been selected 
		 */
		private function checkOptionSelect():void {
			
			var currentOptions:Array = OptionsGrid.members;
			for (var i:int = 0; i < currentOptions.length; i++) {
				var op:FlxTileblock = (currentOptions[i] as FlxTileblock);
				if (op != null && op.overlapsPoint(FlxG.mouse.screenX,FlxG.mouse.screenY)) {
					currentBG.removeFilter();
					currentBG = optionBGs[i];
					currentBG.setFilter(selectFilter);
					grabOption(getIndexFromPoint(op.x, op.y, currentOptionType));
				}
			}
		}
		
		private function grabOption(index:int):void {
			if (currentOptionType == SETTINGS) {
				if (index > 0) {
					changeTileset(index - 1);
					changingStartPosition = false;
				} else {
					selectedOption = optionsString[currentOptionType*100 + index];
					selectedIconImage = optionsImage[currentOptionType*100 + index];
					selectedObjectImage = objectImage[selectedOption];
					selectedImage.loadGraphic(selectedIconImage,false,false,46,46,false);
					changingStartPosition = true;
				}
			} else {
				changingStartPosition = false;
				selectedOption = optionsString[currentOptionType*100 + index];
				selectedIconImage = optionsImage[currentOptionType*100 + index];
				selectedObjectImage = objectImage[selectedOption];
				selectedImage.loadGraphic(selectedIconImage,false,false,46,46,false);
			}
			clearing = selectedOption == CLEAR;
		}
		
		private function changeTileset(newSet:int):void {
			var currentTileset:Array = TileSet.members;
			for (var i:int = 0; i < currentTileset.length; i++) {
				var tile:FlxTileblock = (currentTileset[i] as FlxTileblock);
				if (tile == null) continue;
				if (newSet == GRASS_TILES) {
					tile.loadTiles(Res.grassTiles, CELL_SIZE, CELL_SIZE, 0);
				} else if (newSet == WASTE_TILES) {
					tile.loadTiles(Res.barrenTiles, CELL_SIZE, CELL_SIZE, 0);
				} else if (newSet == VOID_TILES) {
					tile.loadTiles(Res.voidTiles, CELL_SIZE, CELL_SIZE, 0);
				}
			}
			curTileSet = newSet;
		}
		
		private function updateSelectedImage():void {
			if (!mouseOverCanvas()) {
				selectedImage.x = FlxG.mouse.x - 23;
				selectedImage.y = FlxG.mouse.y - 23;
				selectedImage.visible = false;
			} else {
				selectedImage.visible = true;
				var mouseIndex:int = getIndexFromPoint(FlxG.mouse.x, FlxG.mouse.y, MAIN);
				var imageIndex:int = getIndexFromPoint(selectedImage.x, selectedImage.y, MAIN);
				if (mouseIndex != imageIndex) {
					var newPoint:Point = getPointFromIndex(mouseIndex, MAIN);
					selectedImage.x = newPoint.x;
					selectedImage.y = newPoint.y;
				}
			}
		}
		
		/**
		 * Returns cell index that contains this point.
		 */
		public static function getIndexFromPoint(x:int, y:int, type:int):int {
			var xOff:int = 0;
			var yOff:int = 0;
			var spreadX:int = 0;
			var spreadY:int = 0;
			var colNum:int = 0;
			
			if (type == SOURCES) {
				xOff = SOURCES_X_OFFSET;
				yOff = SOURCES_Y_OFFSET;
				colNum = SOURCES_COLS;
				spreadX = SOURCES_X_SPREAD;
				spreadY = SOURCES_Y_SPREAD;
			} else if (type == MONSTERS) {
				xOff = MONSTERS_X_OFFSET;
				yOff = MONSTERS_Y_OFFSET;
				colNum = MONSTERS_COLS;
				spreadX = MONSTERS_X_SPREAD;
				spreadY = MONSTERS_Y_SPREAD;
			} else if (type == TERRAIN) {
				xOff = TERRAIN_X_OFFSET;
				yOff = TERRAIN_Y_OFFSET;
				colNum = TERRAIN_COLS;
				spreadX = TERRAIN_X_SPREAD;
				spreadY = TERRAIN_Y_SPREAD;
			} else if (type == OBSTACLES) {
				xOff = OBSTACLES_X_OFFSET;
				yOff = OBSTACLES_Y_OFFSET;
				colNum = OBSTACLES_COLS;
				spreadX = OBSTACLES_X_SPREAD;
				spreadY = OBSTACLES_Y_SPREAD;
			} else if (type == SETTINGS) {
				if (x >= 527 && x <= 573 && y >= 127 && y <= 173) return 0; //player start pos
				if (x >= 527 && x <= 573 && y >= 202 && y <= 248) return 1; //grass
				if (x >= 583 && x <= 629 && y >= 202 && y <= 248) return 2; //waste
				if (x >= 639 && x <= 685 && y >= 202 && y <= 248) return 3; //void
			} else {
				xOff = X_OFFSET;
				yOff = Y_OFFSET;
				colNum = COLS;
			} 
			var row:int = (y - yOff) / (CELL_SIZE + spreadY);
			var col:int = (x - xOff) / (CELL_SIZE + spreadX);
			return (row * colNum) + col;
		}
		
		/**
		 * Returns upper left point of cell index.
		 */
		public static function getPointFromIndex(index:int, type:int):Point {
			var xOff:int = 0;
			var yOff:int = 0;
			var spreadX:int = 0;
			var spreadY:int = 0;
			var colNum:int = 0;
			
			if (type == SOURCES) {
				xOff = SOURCES_X_OFFSET;
				yOff = SOURCES_Y_OFFSET;
				colNum = SOURCES_COLS;
				spreadX = SOURCES_X_SPREAD;
				spreadY = SOURCES_Y_SPREAD;
			} else if (type == MONSTERS) {
				xOff = MONSTERS_X_OFFSET;
				yOff = MONSTERS_Y_OFFSET;
				colNum = MONSTERS_COLS;
				spreadX = MONSTERS_X_SPREAD;
				spreadY = MONSTERS_Y_SPREAD;
			} else if (type == TERRAIN) {
				xOff = TERRAIN_X_OFFSET;
				yOff = TERRAIN_Y_OFFSET;
				colNum = TERRAIN_COLS;
				spreadX = TERRAIN_X_SPREAD;
				spreadY = TERRAIN_Y_SPREAD;
			} else if (type == OBSTACLES) {
				xOff = OBSTACLES_X_OFFSET;
				yOff = OBSTACLES_Y_OFFSET;
				colNum = OBSTACLES_COLS;
				spreadX = OBSTACLES_X_SPREAD;
				spreadY = OBSTACLES_Y_SPREAD;
			} else {
				xOff = X_OFFSET;
				yOff = Y_OFFSET;
				colNum = COLS;
			}
			
			var row:int = index / colNum;
			var col:int = index - (row * colNum); 
			return new Point(col * CELL_SIZE + xOff + spreadX*col, row * CELL_SIZE + yOff + spreadY*row);
		}
		
		private function drawOptions(type:int):void {
			var rowNum:int = 0;
			var colNum:int = 0;
			var limit:int = 0;
			
			if (type == SOURCES) {
				rowNum = SOURCES_ROWS;
				colNum = SOURCES_COLS;
				limit = SOURCES_LIMIT;
			} else if (type == MONSTERS) {
				rowNum = MONSTERS_ROWS;
				colNum = MONSTERS_COLS;
				limit = MONSTERS_LIMIT;
			} else if (type == TERRAIN) {
				rowNum = TERRAIN_ROWS;
				colNum = TERRAIN_COLS;
				limit = TERRAIN_LIMIT;
			} else if (type == OBSTACLES) {
				rowNum = OBSTACLES_ROWS;
				colNum = OBSTACLES_COLS;
				limit = OBSTACLES_LIMIT;
			}
			
			if (currentOptionType == SETTINGS) this.remove(Settings, true);
			if (type == SETTINGS) this.add(Settings);
			
			currentOptionType = type;
			this.remove(OptionsBGGrid, true);
			OptionsBGGrid = new FlxGroup();
			this.remove(OptionsGrid, true);
			OptionsGrid = new FlxGroup();
			optionBGs = new Dictionary();
			
			//Sources
			if (type != SETTINGS) {
				for (var i:int = 0; i < rowNum; i++) {
					for (var j:int = 0; j < colNum; j++) {
						var index:int = (i*colNum) + j;
						if (index + 1 > limit) break;
						var pos:Point = getPointFromIndex(index,type);
						var bg:FlxTileblock = new FlxTileblock(pos.x - 7, pos.y - 7, 60, 60);
						bg.loadGraphic(Res.iconBG, false,false,60,60,false);
						var b:FlxTileblock;
						b = new FlxTileblock(pos.x, pos.y, 46,46);
						b.loadGraphic(optionsImage[type*100 + index], false, false, 46,46, false);
						OptionsBGGrid.add(bg);
						OptionsGrid.add(b);
						optionBGs[index] = bg;
					}
				}
				
				var clearPos:Point = getPointFromIndex(limit,type);
				var clearBG:FlxTileblock = new FlxTileblock(clearPos.x - 7, clearPos.y - 7, 60, 60);
				clearBG.loadGraphic(Res.iconBG, false,false,60,60,false);
				var clearB:FlxTileblock;
				clearB = new FlxTileblock(clearPos.x, clearPos.y, 46,46);
				clearB.loadGraphic(Res.clearImage, false, false, 46,46, false);
				OptionsBGGrid.add(clearBG);
				OptionsGrid.add(clearB);
				optionBGs[limit] = clearBG;
			} else {
				
				FlxG.stage.addChild(upArrowText);
				FlxG.stage.addChild(downArrowText);
				FlxG.stage.addChild(rightArrowText);
				FlxG.stage.addChild(leftArrowText);
				FlxG.stage.addChild(chickensText);
				
				OptionsBGGrid = settingsBGGrid;
				OptionsGrid = settingsGrid;
				optionBGs = settingsBGs;
			}
			
			this.add(OptionsBGGrid);
			this.add(OptionsGrid);
		}
		
		private function updateUpArrowCount(e:Event):void {
			
			upArrows = int(upArrowText.text);
			if (validated) clearValidation();
		}
		private function updateDownArrowCount(e:Event):void {
			downArrows = int(downArrowText.text);
			if (validated) clearValidation();
		}
		private function updateRightArrowCount(e:Event):void {
			rightArrows = int(rightArrowText.text);
			if (validated) clearValidation();
		}
		private function updateLeftArrowCount(e:Event):void {
			leftArrows = int(leftArrowText.text);
			if (validated) clearValidation();
		}
		
		private function updateChickenCount(e:Event):void {
			chickens = int(chickensText.text);
			if (validated) clearValidation();
		}
		
		private function clearValidation():void {
			submitButton.loadGraphic(Res.presubmitButton, false, false, 100,75,false);
			validated = false;
		}
		
		private function checkOptionsChange():void {
			if (terrainButton.overlapsPoint(FlxG.mouse.screenX,FlxG.mouse.screenY)) {
				if (currentOptionType != TERRAIN) {
					if (currentOptionType == SETTINGS) clearSettings();
					turnOffCurrentOption();
					terrainButton.loadGraphic(Res.TerrainButtonSelected, false, false, 30,30,false);
					drawOptions(TERRAIN);
				}
			} else if (obstaclesButton.overlapsPoint(FlxG.mouse.screenX,FlxG.mouse.screenY)) {
				if (currentOptionType != OBSTACLES) {
					if (currentOptionType == SETTINGS) clearSettings();
					turnOffCurrentOption();
					obstaclesButton.loadGraphic(Res.ObstaclesButtonSelected, false, false, 30,30,false);
					drawOptions(OBSTACLES);
				}
			} else if (sourcesButton.overlapsPoint(FlxG.mouse.screenX,FlxG.mouse.screenY)) {
				if (currentOptionType != SOURCES) {
					if (currentOptionType == SETTINGS) clearSettings();
					turnOffCurrentOption();
					sourcesButton.loadGraphic(Res.SourcesButtonSelected, false, false, 30,30,false);
					drawOptions(SOURCES);
				}
			} else if (monstersButton.overlapsPoint(FlxG.mouse.screenX,FlxG.mouse.screenY)) {
				if (currentOptionType != MONSTERS) {
					if (currentOptionType == SETTINGS) clearSettings();
					turnOffCurrentOption();
					monstersButton.loadGraphic(Res.MonstersButtonSelected, false, false, 30,30,false);
					drawOptions(MONSTERS);
				}
			} else if (settingsButton.overlapsPoint(FlxG.mouse.screenX,FlxG.mouse.screenY)) {
				if (currentOptionType != SETTINGS) {
					turnOffCurrentOption();
					settingsButton.loadGraphic(Res.SettingsButtonSelected, false, false, 30,30,false);
					drawOptions(SETTINGS);
				}
			}
		}
		
		private function clearSettings():void {
			FlxG.stage.removeChild(upArrowText);
			FlxG.stage.removeChild(downArrowText);
			FlxG.stage.removeChild(rightArrowText);
			FlxG.stage.removeChild(leftArrowText);
			FlxG.stage.removeChild(chickensText);
		}
		
		private function turnOffCurrentOption():void {
			if (currentOptionType == TERRAIN) {
				terrainButton.loadGraphic(Res.TerrainButtonNorm, false,false,30,30,false);
			} else if (currentOptionType == OBSTACLES) {
				obstaclesButton.loadGraphic(Res.ObstaclesButtonNorm, false,false,30,30,false);
			} else if (currentOptionType == SOURCES) {
				sourcesButton.loadGraphic(Res.SourcesButtonNorm, false,false,30,30,false);
			} else if (currentOptionType == MONSTERS) {
				monstersButton.loadGraphic(Res.MonstersButtonNorm, false,false,30,30,false);
			} else if (currentOptionType == SETTINGS) {
				settingsButton.loadGraphic(Res.SettingsButtonNorm, false,false,30,30,false);
			}
		}
		
		private function checkHover():void {
			
			if (terrainButton.overlapsPoint(FlxG.mouse.screenX,FlxG.mouse.screenY)) {
				if (!terrainOverlapped) {
					terrainButton.setFilter(hoverFilter);
					terrainOverlapped = true;
				}
			} else {
				if (terrainOverlapped) {
					terrainButton.removeFilter();
					terrainOverlapped = false;
				}
			}
			if (obstaclesButton.overlapsPoint(FlxG.mouse.screenX,FlxG.mouse.screenY)) {
				if (!obstaclesOverlapped) {
					obstaclesButton.setFilter(hoverFilter);
					obstaclesOverlapped = true;
				}
			} else {
				if (obstaclesOverlapped) {
					obstaclesButton.removeFilter();
					obstaclesOverlapped = false;
				}
			}
			if (sourcesButton.overlapsPoint(FlxG.mouse.screenX,FlxG.mouse.screenY)) {
				if (!sourcesOverlapped) {
					sourcesButton.setFilter(hoverFilter);
					sourcesOverlapped = true;
				}
			} else {
				if (sourcesOverlapped) {
					sourcesButton.removeFilter();
					sourcesOverlapped = false;
				}
			}
			if (monstersButton.overlapsPoint(FlxG.mouse.screenX,FlxG.mouse.screenY)) {
				if (!monstersOverlapped) {
					monstersButton.setFilter(hoverFilter);
					monstersOverlapped = true;
				}
			} else {
				if (monstersOverlapped) {
					monstersButton.removeFilter();
					monstersOverlapped = false;
				}
			}
			if (settingsButton.overlapsPoint(FlxG.mouse.screenX,FlxG.mouse.screenY)) {
				if (!settingsOverlapped) {
					settingsButton.setFilter(hoverFilter);
					settingsOverlapped = true;
				}
			} else {
				if (settingsOverlapped) {
					settingsButton.removeFilter();
					settingsOverlapped = false;
				}
			}
		}
		
		private function getCurMap():PuzzleSpecification {
			var curMap:String = createdMap[0];
			
			for (var i:int = 1; i < ROWS*COLS; i++) {
				if (createdMap[i] == NONE) {
					curMap += ",0";
				} else {
					curMap += "," + createdMap[i];
				}
			}
			
			
			var count:Array = new Array();
			if (chickens > 0) {
				count.push("1");
				for (var j:int = 1; j < chickens; j++) {
					count.push("1");
				}
			}
			
			var arrows:Array = new Array(upArrows, downArrows, leftArrows, rightArrows);
			var spec:PuzzleSpecification = new PuzzleSpecification(curMap,curTileSet,arrows,count,0);
			return spec;
		}
	}
}